package com.example.java_chatroom.controller;

import com.example.java_chatroom.componet.OnlineUserManager;
import com.example.java_chatroom.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

@Component
public class WebSocketController extends TextWebSocketHandler {
    // 用户管理
    @Resource
    private OnlineUserManager onlineUserManager;

    @Resource
    private MessageSessionMapper messageSessionMapper;

    @Resource
    MessageMapper messageMapper;

    @Resource
    FriendRequestMapper friendRequestMapper;

    // JSON和java对象的相互转换
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("[WebSocketController] 连接成功");
        //获取WebSocketSession中存放的user对象
        User user = (User)session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        //用户上线
        onlineUserManager.online(user, session);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("[WebSocketController] 连接异常");
        User user = (User)session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        //用户下线
        onlineUserManager.offline(user, session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("[WebSocketController] 连接关闭");
        User user = (User)session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        //用户下线
        onlineUserManager.offline(user, session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 在WebSocket协议中要发送的信息是保存在payload（载荷）中的，TextMessage类是用于存放WebSocket协议中的载荷数据的文本类型
        // 在TextMessage这个类中通过getPayload可以得到载荷中的数据，在这里载荷中存放的是一个json字符串，是文本类型的
        System.out.println("[WebSocketController] 接收消息成功：" + message.toString());
        User user = (User)session.getAttributes().get("user");
        if (user == null) {
            return;
        }

        // 解析为树结构 直接访问json中的字段
        JsonNode rootNode = objectMapper.readTree(message.getPayload());
        String type = rootNode.get("type").asText();

        //通过type来判断当前的请求是哪种类型的
        if ("message" .equals(type)) {
            // 进行消息的转发
            MessageRequest req = objectMapper.readValue(message.getPayload(), MessageRequest.class);
            transferMessage(user, req);
        } else if ("friendRequest".equals(type)){
            FriendRequest req = objectMapper.readValue(message.getPayload(), FriendRequest.class);
            transferRequest(user, req);
        } else if ("delSession".equals(type)) {
            DelSessionReq req = objectMapper.readValue(message.getPayload(), DelSessionReq.class);
            transferDelSession(user, req);
        } else if ("delFriend".equals(type)) {
            DelFriendReq req = objectMapper.readValue(message.getPayload(), DelFriendReq.class);
            transferDelFriend(user, req);
        } else {
            System.out.println("[WebSocketController] type有误" + message.getPayload());
        }
    }

    // 通知被删除用户的客户端
    private void transferDelFriend(User user, DelFriendReq req) throws IOException {
        System.out.println("被删除好友的Id："+req.getFriendId());
        WebSocketSession websocketSession = onlineUserManager.getSession(req.getFriendId());
        // 如果用户在线则把这个删除的通知转发给被删除好友的客户端
        if (websocketSession != null) {
            // 转为JSON格式
            String respJson = objectMapper.writeValueAsString(req);
            websocketSession.sendMessage(new TextMessage(respJson));
            System.out.println("发送删除好友通知成功！");
        }
    }

    // 通知会话中的另一个客户端会话被删除的操作
    private void transferDelSession(User user, DelSessionReq req) throws IOException {
        System.out.println("[transferDelSession] 被删除会话的信息："+req);
        // 找到当前会话中的另一个用户
         List<Friend> friends = messageSessionMapper.getFriendsBySessionId(req.getSessionId(), user.getUserId());
         Friend friend = friends.get(0);
        WebSocketSession webSocketSession = onlineUserManager.getSession(friend.getFriendId());
        // 会话中的另一个用户在线的情况下才进行通知
        if (webSocketSession != null) {
            // 转为JSON格式
            String respJson = objectMapper.writeValueAsString(req);
            // 转发给客户端
            webSocketSession.sendMessage(new TextMessage(respJson));
            System.out.println("[transferDelSession] 转发删除会话消息成功！");
        }

    }

    // 转发好友申请的操作
    private void transferRequest(User user, FriendRequest req) throws IOException {
        // 构造resp
        FriendRequest resp = new FriendRequest();
        resp.setType("friendRequest");
        resp.setContent(req.getContent());
        resp.setFromName(req.getFromName());
        resp.setFromId(req.getFromId());
        resp.setToUserId(req.getToUserId());
        // 转为JSON格式
        String respJson = objectMapper.writeValueAsString(resp);

        // 先在数据库中查询看看当前请求是不是已经发送过
        FriendRequest friendRequest = friendRequestMapper.selectRequest(req);
        // 如果在数据库中存在则不再执行后续的代码
        if (friendRequest != null) {
            System.out.println("[selectRequest] 该请求已经存在！");
            return;
        }

        // 获取目标用户的websocketsession
        WebSocketSession webSocketSession = onlineUserManager.getSession(req.getToUserId());

        // 如果用户在线则把直接把请求发送
        if (webSocketSession != null) {
            webSocketSession.sendMessage(new TextMessage(respJson));
        }

        //打印日志
        System.out.println("[transferRequest] respJson 转发好友申请成功：" + respJson);

        // 将这条用户申请好友请求插入到数据库中
        try {
            friendRequestMapper.addFriendRequest(resp);
        } catch (Exception e) {
            System.out.println("[addFriendRequest] 重复请求，无法插入数据库！");
        }

    }

    //进行消息的转发
    private void transferMessage(User fromUser, MessageRequest req) throws IOException {
        // 1.构造响应
        MessageResponse resp = new MessageResponse();
        resp.setType("message");
        resp.setFromId(fromUser.getUserId());
        resp.setFromName(fromUser.getUsername());
        resp.setContent(req.getContent());
        resp.setSessionId(req.getSessionId());
        // 转为JSON格式
        String respJson = objectMapper.writeValueAsString(resp);

        // 2.给当前会话中的每个用户都发送一个响应，包括自己（方便显示在前端页面）
        // getFriendsBySessionId方法会返回除了当前用户之外的用户
        List<Friend> friends = messageSessionMapper.getFriendsBySessionId(req.getSessionId(), fromUser.getUserId());
        // 将自己也放入到列表中
        Friend myself = new Friend();
        myself.setFriendId(fromUser.getUserId());
        myself.setFriendName(fromUser.getUsername());
        friends.add(myself);

        // 给每个用户的webSocketSession中发送消息
        for (Friend friend : friends) {
            // 获取相应好友的webSocketSession
            WebSocketSession webSocketSession = onlineUserManager.getSession(friend.getFriendId());
            // webSocketSession等于空表示这个好友没有上线，无法获取到他的webSocketSession
            // 无法给离线的用户在这里发送消息
            if (webSocketSession == null) {
                continue;
            }
            // 将这个消息发送给相应的客户端的会话中（发给了前端）
            webSocketSession.sendMessage(new TextMessage(respJson));
        }

        //打印日志
        System.out.println("[transferMessage] respJson 转发消息成功：" + respJson);

        // 3.将发送的消息加入数据库中，后续用户下线再上线也能看到历史消息，包括发送消息时离线的用户，登录后也能看到消息
        // 构造message记录
        Message message = new Message();
        message.setFromId(fromUser.getUserId());
        message.setContent(resp.getContent());
        message.setSessionId(req.getSessionId());
        messageMapper.addMessage(message);
    }

    public void sendSystemMessage(int sessionId, String content, int fromUserId, String fromUserName) throws IOException {
        // 构造请求添加为好友的那个用户
        User fromUser = new User();
        fromUser.setUserId(fromUserId);
        fromUser.setUsername(fromUserName);
        System.out.println("[sendSystemMessage] fromUser: "+fromUser.toString());

        // 构造这条发送请求时输入的消息
        MessageRequest req = new MessageRequest();
        req.setType("message");
        req.setSessionId(sessionId);
        req.setContent(content);
        System.out.println("申请理由："+req.toString());

        transferMessage(fromUser, req);
    }
}
